#include "Shader.h"

#include <Runtime/Graphics/Device/GraphicsDevice.h>
#include <Runtime/Graphics/Shader/ShaderReader.h>


Shader::Shader(std::shared_ptr<GraphicsDevice> device, const ShaderDesc& desc) {
	mOwnerDevice = device;
	mEntryPoint = desc.EntryPoint;
	mShaderName = desc.ShaderName;
	mShaderType = desc.Type;
	mShaderModel = desc.ShaderModel;


	ComPtr<ID3DBlob> errorBlob;
	std::string shaderBlob = ShaderReader::ReadShaderFile(mShaderName);
	D3DCompile(shaderBlob.c_str(), shaderBlob.length(), nullptr, nullptr, nullptr, 
		mEntryPoint.c_str(), mShaderModel.c_str(), D3DCOMPILE_ENABLE_STRICTNESS, 0, 
		mShaderBlob.GetAddressOf(), errorBlob.GetAddressOf());
	if (errorBlob.Get() != nullptr && errorBlob->GetBufferPointer() != nullptr) {
		DEV_LOG(TE_FATAL, "Shader", "Failed to compile shader: %s\n%s\n", mShaderName.c_str(), (char*)errorBlob->GetBufferPointer());
	}

	HRESULT result = S_OK;
	switch (mShaderType) {
	case ShaderType::VERTEX_SHADER:
		result = device->GetD3D11Device()->CreateVertexShader(mShaderBlob->GetBufferPointer(),
			mShaderBlob->GetBufferSize(), nullptr,mVertexShader.GetAddressOf());
		break;
	case ShaderType::PIXEL_SHADER:
		result = device->GetD3D11Device()->CreatePixelShader(mShaderBlob->GetBufferPointer(),
			mShaderBlob->GetBufferSize(), nullptr, mPixelShader.GetAddressOf());
		break;
	case ShaderType::GEOMETRY_SHADER:
		result = device->GetD3D11Device()->CreateGeometryShader(mShaderBlob->GetBufferPointer(),
			mShaderBlob->GetBufferSize(), nullptr, mGeometryShader.GetAddressOf());
		break;
	case ShaderType::HULL_SHADER:
		result = device->GetD3D11Device()->CreateHullShader(mShaderBlob->GetBufferPointer(),
			mShaderBlob->GetBufferSize(), nullptr, mHullShader.GetAddressOf());
		break;
	case ShaderType::DOMAIN_SHADER:
		result = device->GetD3D11Device()->CreateDomainShader(mShaderBlob->GetBufferPointer(),
			mShaderBlob->GetBufferSize(), nullptr, mDomainShader.GetAddressOf());
		break;
	case ShaderType::COMPUTE_SHADER:
		result = device->GetD3D11Device()->CreateComputeShader(mShaderBlob->GetBufferPointer(),
			mShaderBlob->GetBufferSize(), nullptr, mComputeShader.GetAddressOf());
		break;
	default:
		DEV_LOG(TE_FATAL, "Shader", "Unknown Shader Type: %d", mShaderType);
		break;
	}

	DEV_ASSERT(SUCCEEDED(result), "Shader", "Failed to create shader(Type: %d).", mShaderType);
}
